home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / perl5 / Net / DBus / Test / MockConnection.pm next >
Encoding:
Perl POD Document  |  2008-02-20  |  11.9 KB  |  461 lines

  1. # -*- perl -*-
  2. #
  3. # Copyright (C) 2004-2006 Daniel P. Berrange
  4. #
  5. # This program is free software; You can redistribute it and/or modify
  6. # it under the same terms as Perl itself. Either:
  7. #
  8. # a) the GNU General Public License as published by the Free
  9. #   Software Foundation; either version 2, or (at your option) any
  10. #   later version,
  11. #
  12. # or
  13. #
  14. # b) the "Artistic License"
  15. #
  16. # The file "COPYING" distributed along with this file provides full
  17. # details of the terms and conditions of the two licenses.
  18.  
  19. =pod
  20.  
  21. =head1 NAME
  22.  
  23. Net::DBus::Test::MockConnection - Fake a connection to the bus unit testing
  24.  
  25. =head1 SYNOPSIS
  26.  
  27.   use Net::DBus;
  28.  
  29.   my $bus = Net::DBus->test
  30.  
  31.   # Register a service, and the objec to be tested
  32.   use MyObject
  33.   my $service = $bus->export_service("org.example.MyService");
  34.   my $object = MyObject->new($service);
  35.  
  36.  
  37.   # Acquire the service & do tests
  38.   my $remote_service = $bus->get_service('org.example.MyService');
  39.   my $remote_object = $service->get_object("/org/example/MyObjct");
  40.  
  41.   # This traverses the mock connection, eventually
  42.   # invoking 'testSomething' on the $object above.
  43.   $remote_object->testSomething()
  44.  
  45. =head1 DESCRIPTION
  46.  
  47. This object provides a fake implementation of the L<Net::DBus::Binding::Connection>
  48. enabling a pure 'in-memory' message bus to be mocked up. This is intended to
  49. facilitate creation of unit tests for services which would otherwise need to 
  50. call out to other object on a live message bus. It is used as a companion to
  51. the L<Net::DBus::Test::MockObject> module which is how fake objects are to be
  52. provided on the fake bus.
  53.  
  54. =head1 METHODS
  55.  
  56. =over 4
  57.  
  58. =cut
  59.  
  60. package Net::DBus::Test::MockConnection;
  61.  
  62. use strict;
  63. use warnings;
  64.  
  65. use Net::DBus::Error;
  66. use Net::DBus::Test::MockMessage;
  67. use Net::DBus::Binding::Message::MethodCall;
  68. use Net::DBus::Binding::Message::MethodReturn;
  69. use Net::DBus::Binding::Message::Error;
  70. use Net::DBus::Binding::Message::Signal;
  71.  
  72. =item my $con = Net::DBus::Test::MockConnection->new()
  73.  
  74. Create a new mock connection object instance. It is not usually
  75. neccessary to create instances of this object directly, instead
  76. the C<test> method on the L<Net::DBus> object can be used to
  77. get a handle to a test bus.
  78.  
  79. =cut
  80.  
  81. sub new {
  82.     my $class = shift;
  83.     my $self = {};
  84.     
  85.     $self->{replies} = [];
  86.     $self->{signals} = [];
  87.     $self->{objects} = {};
  88.     $self->{objectTrees} = {};
  89.     $self->{filters} = [];
  90.     
  91.     bless $self, $class;
  92.     
  93.     return $self;
  94. }
  95.  
  96. =item $con->send($message)
  97.  
  98. Send a message over the mock connection. If the message is
  99. a method call, it will be dispatched straight to any corresponding
  100. mock object registered. If the mesage is an error or method return
  101. it will be made available as a return value for the C<send_with_reply_and_block>
  102. method. If the message is a signal it will be queued up for processing
  103. by the C<dispatch> method. 
  104.  
  105. =cut
  106.  
  107.  
  108. sub send {
  109.     my $self = shift;
  110.     my $msg = shift;
  111.  
  112.     if ($msg->get_type() == &Net::DBus::Binding::Message::MESSAGE_TYPE_METHOD_CALL) {
  113.     $self->_call_method($msg);
  114.     } elsif ($msg->get_type() == &Net::DBus::Binding::Message::MESSAGE_TYPE_METHOD_RETURN ||
  115.          $msg->get_type() == &Net::DBus::Binding::Message::MESSAGE_TYPE_ERROR) {
  116.     push @{$self->{replies}}, $msg;
  117.     } elsif ($msg->get_type() == &Net::DBus::Binding::Message::MESSAGE_TYPE_SIGNAL) {
  118.     push @{$self->{signals}}, $msg;
  119.     } else {
  120.     die "unhandled type of message " . ref($msg);
  121.     }
  122. }
  123.  
  124.  
  125. =item $bus->request_name($service_name)
  126.  
  127. Pretend to send a request to the bus registering the well known 
  128. name specified in the C<$service_name> parameter. In reality
  129. this is just a no-op giving the impression that the name was
  130. successfully registered.
  131.  
  132. =cut
  133.  
  134. sub request_name {
  135.     my $self = shift;
  136.     my $name = shift;
  137.     my $flags = shift;
  138.     
  139.     # XXX do we care about this for test cases? probably not...
  140.     # ....famous last words
  141. }
  142.  
  143. =item my $reply = $con->send_with_reply_and_block($msg)
  144.  
  145. Send a message over the mock connection and wait for a
  146. reply. The C<$msg> should be an instance of C<Net::DBus::Binding::Message::MethodCall>
  147. and the return C<$reply> will be an instance of C<Net::DBus::Binding::Message::MethodReturn>.
  148. It is also possible that an error will be thrown, with
  149. the thrown error being blessed into the C<Net::DBus::Error>
  150. class.
  151.  
  152. =cut
  153.  
  154. sub send_with_reply_and_block {
  155.     my $self = shift;
  156.     my $msg = shift;
  157.     my $timeout = shift;
  158.     
  159.     $self->send($msg);
  160.     
  161.     if ($#{$self->{replies}} == -1) {
  162.     die "no reply for " . $msg->get_path . "->" . $msg->get_member . " received within timeout";
  163.     }
  164.     
  165.     my $reply = shift @{$self->{replies}};
  166.     if ($#{$self->{replies}} != -1) {
  167.     die "too many replies received";
  168.     }
  169.  
  170.     if ($reply->get_type() == &Net::DBus::Binding::Message::MESSAGE_TYPE_ERROR) {
  171.     my $iter = $reply->iterator;
  172.     my $desc = $iter->get_string;
  173.     die Net::DBus::Error->new(name => $reply->get_error_name,
  174.                   message => $desc);
  175.     }
  176.  
  177.     return $reply;
  178. }
  179.  
  180. =item $con->dispatch;
  181.  
  182. Dispatches any pending messages in the incoming queue
  183. to their message handlers. This method should be called
  184. by test suites whenever they anticipate that there are
  185. pending signals to be dealt with.
  186.  
  187. =cut
  188.  
  189. sub dispatch {
  190.     my $self = shift;
  191.     
  192.     my @signals = @{$self->{signals}};
  193.     $self->{signals} = [];
  194.     foreach my $msg (@signals) {
  195.     foreach my $cb (@{$self->{filters}}) {
  196.         # XXX we should worry about return value...
  197.         &$cb($self, $msg);
  198.     }
  199.     }
  200. }
  201.  
  202. =item $con->add_filter($coderef);
  203.  
  204. Adds a filter to the connection which will be invoked whenever a
  205. message is received. The C<$coderef> should be a reference to a
  206. subroutine, which returns a true value if the message should be
  207. filtered out, or a false value if the normal message dispatch
  208. should be performed.
  209.  
  210. =cut
  211.  
  212. sub add_filter {
  213.     my $self = shift;
  214.     my $cb = shift;
  215.     
  216.     push @{$self->{filters}}, $cb;
  217. }
  218.  
  219. =item $bus->add_match($rule)
  220.  
  221. Register a signal match rule with the bus controller, allowing
  222. matching broadcast signals to routed to this client. In reality
  223. this is just a no-op giving the impression that the match was
  224. successfully registered.
  225.  
  226. =cut
  227.  
  228. sub add_match {
  229.     my $self = shift;
  230.     my $rule = shift;
  231.     
  232.     # XXX do we need to implement anything ? probably not 
  233.     # nada
  234. }
  235.  
  236. =item $bus->remove_match($rule)
  237.  
  238. Unregister a signal match rule with the bus controller, preventing
  239. further broadcast signals being routed to this client. In reality
  240. this is just a no-op giving the impression that the match was
  241. successfully unregistered.
  242.  
  243. =cut
  244.  
  245. sub remove_match {
  246.     my $self = shift;
  247.     my $rule = shift;
  248.     
  249.     # XXX do we need to implement anything ? probably not 
  250.     # nada
  251. }
  252.  
  253.  
  254. =item $con->register_object_path($path, \&handler)
  255.  
  256. Registers a handler for messages whose path matches
  257. that specified in the C<$path> parameter. The supplied
  258. code reference will be invoked with two parameters, the
  259. connection object on which the message was received,
  260. and the message to be processed (an instance of the
  261. C<Net::DBus::Binding::Message> class).
  262.  
  263. =cut
  264.  
  265. sub register_object_path {
  266.     my $self = shift;
  267.     my $path = shift;
  268.     my $code = shift;
  269.     
  270.     $self->{objects}->{$path} = $code;
  271. }
  272.  
  273. =item $con->register_fallback($path, \&handler)
  274.  
  275. Registers a handler for messages whose path starts with 
  276. the prefix specified in the C<$path> parameter. The supplied
  277. code reference will be invoked with two parameters, the
  278. connection object on which the message was received,
  279. and the message to be processed (an instance of the
  280. C<Net::DBus::Binding::Message> class).
  281.  
  282. =cut
  283.  
  284. sub register_fallback {
  285.     my $self = shift;
  286.     my $path = shift;
  287.     my $code = shift;
  288.     
  289.     $self->{objects}->{$path} = $code;
  290.     $self->{objectTrees}->{$path} = $code;
  291. }
  292.  
  293. =item $con->unregister_object_path($path)
  294.  
  295. Unregisters the handler associated with the object path C<$path>. The
  296. handler would previously have been registered with the C<register_object_path>
  297. or C<register_fallback> methods.
  298.  
  299. =cut
  300.  
  301. sub unregister_object_path {
  302.     my $self = shift;
  303.     my $path = shift;
  304.     
  305.     delete $self->{objects}->{$path};
  306. }
  307.  
  308. sub _call_method {
  309.     my $self = shift;
  310.     my $msg = shift;
  311.  
  312.     if (exists $self->{objects}->{$msg->get_path}) {
  313.     my $cb = $self->{objects}->{$msg->get_path};
  314.     &$cb($self, $msg);
  315.     } else {
  316.     foreach my $path (reverse sort { $a cmp $b } keys %{$self->{objectTrees}}) {
  317.         if ((index $msg->get_path, $path) == 0) {
  318.         my $cb = $self->{objects}->{$path};
  319.         &$cb($self, $msg);
  320.         return;
  321.         }
  322.     }
  323.     if ($msg->get_path eq "/org/freedesktop/DBus") {
  324.         if ($msg->get_member eq "GetNameOwner") {
  325.         my $reply = $self->make_method_return_message($msg);
  326.         my $iter = $reply->iterator(1);
  327.         $iter->append(":1.1");
  328.         $self->send($reply);
  329.         }
  330.     }
  331.     }
  332. }
  333.  
  334. =item my $msg = $con->make_error_message($replyto, $name, $description)
  335.  
  336. Creates a new message, representing an error which occurred during
  337. the handling of the method call object passed in as the C<$replyto>
  338. parameter. The C<$name> parameter is the formal name of the error
  339. condition, while the C<$description> is a short piece of text giving
  340. more specific information on the error.
  341.  
  342. =cut
  343.  
  344. sub make_error_message {
  345.     my $self = shift;
  346.     my $replyto = shift;
  347.     my $name = shift;
  348.     my $description = shift;
  349.  
  350.     if (1) {
  351.     return Net::DBus::Test::MockMessage->new_error(replyto => $replyto,
  352.                                error_name => $name,
  353.                                error_description => $description);
  354.     } else {
  355.     return Net::DBus::Binding::Message::Error->new(replyto => $replyto,
  356.                                name => $name,
  357.                                description => $description);
  358.     }
  359. }
  360.  
  361. =item my $call = $con->make_method_call_message(
  362.   $service_name, $object_path, $interface, $method_name);
  363.  
  364. Create a message representing a call on the object located at
  365. the path C<$object_path> within the client owning the well-known
  366. name given by C<$service_name>. The method to be invoked has
  367. the name C<$method_name> within the interface specified by the
  368. C<$interface> parameter.
  369.  
  370. =cut
  371.  
  372. sub make_method_call_message {
  373.     my $self = shift;
  374.     my $service_name = shift;
  375.     my $object_path = shift;
  376.     my $interface = shift;
  377.     my $method_name = shift;
  378.  
  379.     if (1) {
  380.     return Net::DBus::Test::MockMessage->new_method_call(destination => $service_name,
  381.                                  path => $object_path,
  382.                                  interface => $interface,
  383.                                  member => $method_name);
  384.     } else {
  385.     return Net::DBus::Binding::Message::MethodCall->new(service_name => $service_name,
  386.                                 object_path => $object_path,
  387.                                 interface => $interface,
  388.                                 method_name => $method_name);
  389.     }
  390. }
  391.  
  392. =item my $msg = $con->make_method_return_message($replyto)
  393.  
  394. Create a message representing a reply to the method call message passed in
  395. the C<$replyto> parameter.
  396.  
  397. =cut
  398.  
  399.  
  400. sub make_method_return_message {
  401.     my $self = shift;
  402.     my $replyto = shift;
  403.  
  404.     if (1) {
  405.     return Net::DBus::Test::MockMessage->new_method_return(replyto => $replyto);
  406.     } else {
  407.     return Net::DBus::Binding::Message::MethodReturn->new(call => $replyto);
  408.     }
  409. }
  410.  
  411.  
  412. =item my $msg = $con->make_signal_message($object_path, $interface, $signal_name);
  413.  
  414. Creates a new message, representing a signal [to be] emitted by
  415. the object located under the path given by the C<$object_path>
  416. parameter. The name of the signal is given by the C<$signal_name>
  417. parameter, and is scoped to the interface given by the
  418. C<$interface> parameter.
  419.  
  420. =cut
  421.  
  422. sub make_signal_message {
  423.     my $self = shift;
  424.     my $object_path = shift;
  425.     my $interface = shift;
  426.     my $signal_name = shift;
  427.  
  428.     if (1) {
  429.     return Net::DBus::Test::MockMessage->new_signal(object_path => $object_path,
  430.                             interface => $interface,
  431.                             signal_name => $signal_name);
  432.     } else {
  433.     return Net::DBus::Binding::Message::Signal->new(object_path => $object_path,
  434.                             interface => $interface,
  435.                             signal_name => $signal_name);
  436.     }
  437. }
  438.  
  439.  
  440. 1;
  441.  
  442. =pod
  443.  
  444. =back
  445.  
  446. =head1 BUGS
  447.  
  448. It doesn't completely replicate the API of L<Net::DBus::Binding::Connection>, 
  449. merely enough to make the high level bindings work in a test scenario.
  450.  
  451. =head1 SEE ALSO
  452.  
  453. L<Net::DBus>, L<Net::DBus::Test::MockObject>, L<Net::DBus::Binding::Connection>,
  454. L<http://www.mockobjects.com/Faq.html>
  455.  
  456. =head1 COPYRIGHT
  457.  
  458. Copyright 2005 Daniel Berrange <dan@berrange.com>
  459.  
  460. =cut
  461.